/*
 * @Description:
 * @Author: Cxy
 * @Date: 2023-04-25 09:54:59
 * @LastEditors: Cxy
 * @LastEditTime: 2025-10-20 20:38:58
 * @FilePath: \xy-admin\play\src\router\utils.ts
 */
import router from './index'
import type { RouteConfigInter } from './type'
import { powerStore } from '@/stores/power'

/**
 * @description: 组装路由 将路由组装成多维路由表
 */
export const assemblyRO = (routes: Array<RouteConfigInter>) =>
  routes.reduce(
    (prev: any, c: RouteConfigInter) => {
      const indexR = prev[0]
      if (c.path === '/') {
        Object.assign(indexR, c)
      } else if (c.meta?.noLayout) {
        prev.push(c)
      } else {
        indexR.children.push({ ...c })
      }
      if (!indexR.redirect) indexR.redirect = c.path
      return prev
    },
    [{ children: [] }]
  )

/**
 * @description: 路由排序 只能对一级路由生效 如果后端返回的排序 排序字段需要是 sort
 * @sortRD 路由排列顺序，没有设置按文件默认顺序排列(路由path与文件名须保持一致，也可直接写入完整一级路由path)
 */
const sortRD: Array<string> = ['/home', '/example', '/menu', '/permission', '/largeScreenPlay', '/error']
export const sortRO = (routes: Array<RouteConfigInter>) => {
  routes.forEach((c, i) => {
    const index = sortRD.indexOf(c.path)
    c.sort ?? (c.sort = index === -1 ? routes.length + i : index)
  })
  return routes.sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0))
}

/**
 * @description: 动态路由判断正则
 */
// export const dynamicRegExp = /:.*|\/:.*/gm
export const dynamicRegExp = /\/?:[\w|?|\\|(|)|+|.|*]*/g

/**
 * @description: 拼接 完整路由path 重定向redirect 自动填充name 动态路由处理
 * @param {string} upperPath：上级path
 */
export const splicingRO = (routes: Array<RouteConfigInter>, upperPath?: string) => {
  routes.forEach(c => {
    if (!(c.path.indexOf('/') === 0)) c.path = upperPath + c.path
    const dyD = c.path.match(dynamicRegExp)
    /* 存放动态路由path 判断页面跳转菜单锁定 */
    if (dyD) {
      const path = c.path.replace(dynamicRegExp, '')
      powerStore.dynamicRD.push({
        path,
        dyRegExp: `^${path.replaceAll(/\//g, '\\/')}${`(\\/?[\\w\\-\\.,@?^=%&:~\\+#]*){0,${dyD.length}${'}$'}`}`
      })
    }
    if (!c?.name) c.name = c.path
    if (c.component && c.meta?.keepAlive) {
      const com = c.component
      c.component = () => (com as any)().then((cc: any) => ({ ...cc.default, name: c.name }))
    }

    if (c.children?.length) {
      const subroutePath = c.children[0].path.replace(dynamicRegExp, '')
      if (!c.redirect) c.redirect = c.path + (subroutePath.indexOf('/') === 0 ? '' : '/') + subroutePath
      splicingRO(c.children, `${c.path}/`)
    }
  })
  return routes
}

/**
 * @description: 过滤需要隐藏的路由
 * @param {Array} routes
 * @return {Array}
 */
export const filterMenuRO = (routes: Array<RouteConfigInter>): Array<RouteConfigInter> => {
  const newTree = routes.filter(c => !c.meta?.isShow)
  newTree.forEach(c => c.children && (c.children = filterMenuRO(c.children)))
  return newTree
}

/**
 * @description: 查找顶级路由path
 * @param {string} path 当前path
 * @return {Array} 当前路由的所有父级path
 */
export const topLevelRO = (routes: Array<RouteConfigInter>, path: string): Array<string> => {
  const findPath = (routes: Array<RouteConfigInter>, path: string, topLevePath: Array<string>) => {
    for (const c of routes) {
      const curentPath = c.path.replace(dynamicRegExp, '')
      // 找到path则返回父级path
      if (curentPath === path) return topLevePath
      // children不存在或为空则不递归
      if (!c.children || !c.children.length) continue
      // 往下查找时将当前path入栈
      topLevePath.push(curentPath)
      if (findPath(c.children, path, topLevePath).length) return topLevePath
      // 深度遍历查找未找到时当前path 出栈
      topLevePath.pop()
    }
    // 未找到时返回空数组
    return []
  }
  return findPath(routes, path, [])
}

/**
 * @description: 动态路由菜单定位处理 https://router.vuejs.org/zh/guide/essentials/dynamic-matching.html
 * @param {string} path 当前path
 * @return {string} 处理后path
 */
export const dynamicProcessRO = (path: string): string => {
  const dynamicRD = powerStore.dynamicRD
  const dyFilter = dynamicRD.filter((c: DynamicInter) => new RegExp(c.dyRegExp).test(path))
  return dyFilter.length ? dyFilter[0].path : path
}

/**
 * @description: 动态路由添加
 * @param {Array} routes
 */
export const addRouterRO = (routes: Array<RouteConfigInter>) => {
  routes.forEach((c: any) => {
    router.addRoute(c)
  })
  const isNoFound = router.hasRoute('noFound')
  if (isNoFound) router.removeRoute('noFound')
  router.addRoute({
    path: '/:pathMatch(.*)',
    redirect: '/error'
  })
}

/**
 * @description: 组装路由 component https://cn.vitejs.dev/guide/features.html#glob-import
 *              此处由于是动态导入的，在其他页面如果有通过import导入下面匹配的相同文件 .vue，就会造成同一个模块同时被静态和动态导入，
 *              Vite 会优先将其视为静态依赖，忽略动态导入的 chunk 拆分意图，于是给出警告。
 * @param {*}
 * @return {*}
 */
const componentVue = import.meta.glob(['!**/logo.vue', '/src/views/**/*.{vue,tsx}'])
const componentKey = Object.keys(componentVue)
export const findComponentsRO = (routes: Array<RouteConfigInter>) => {
  routes.forEach((c: any) => {
    if (c.children && !c.component) {
      findComponentsRO(c.children)
    } else {
      const index = c?.component
        ? componentKey.findIndex(ev => ev.includes(c.component))
        : componentKey.findIndex(ev => ev.includes(c.path))
      c.component = componentVue[componentKey[index]]
      if (c.children) findComponentsRO(c.children)
    }
  })
  return routes
}
